home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / m4-1_0_3.lha / m4-1.0.3 / debug.c < prev    next >
C/C++ Source or Header  |  1992-12-19  |  8KB  |  379 lines

  1. /*
  2.  * GNU m4 -- A simple macro processor
  3.  * Copyright (C) 1991, 1992 Free Software Foundation, Inc.
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2, or (at your option)
  8.  * any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. #include "m4.h"
  21.  
  22. /* File for debugging output.  */
  23. static FILE *debug;
  24.  
  25. /* Obstack for trace messages.  */
  26. static struct obstack trace;
  27.  
  28. extern int expansion_level;
  29.  
  30. /*
  31.  * Initialise the debugging module.
  32.  */
  33. void
  34. debug_init (void)
  35. {
  36.   debug = stderr;
  37.   obstack_init (&trace);
  38. }
  39.  
  40.  
  41. /*
  42.  * Function to decode the debugging flags OPTS.  Used by main (-dXXX)
  43.  * and the builtin debugmode ().
  44.  */
  45. int
  46. debug_decode (char *opts)
  47. {
  48.   int level;
  49.  
  50.   if (opts == NULL || *opts == '\0')
  51.     level = DEBUG_TRACE_DEFAULT;
  52.   else
  53.     {
  54.       for (level = 0; *opts; opts++)
  55.     {
  56.       switch (*opts)
  57.         {
  58.         case 'a':
  59.           level |= DEBUG_TRACE_ARGS;
  60.           break;
  61.         case 'e':
  62.           level |= DEBUG_TRACE_EXPANSION;
  63.           break;
  64.         case 'q':
  65.           level |= DEBUG_TRACE_QUOTE;
  66.           break;
  67.         case 't':
  68.           level |= DEBUG_TRACE_ALL;
  69.           break;
  70.         case 'l':
  71.           level |= DEBUG_TRACE_LINE;
  72.           break;
  73.         case 'f':
  74.           level |= DEBUG_TRACE_FILE;
  75.           break;
  76.         case 'p':
  77.           level |= DEBUG_TRACE_PATH;
  78.           break;
  79.         case 'c':
  80.           level |= DEBUG_TRACE_CALL;
  81.           break;
  82.         case 'i':
  83.           level |= DEBUG_TRACE_INPUT;
  84.           break;
  85.         case 'x':
  86.           level |= DEBUG_TRACE_CALLID;
  87.           break;
  88.         case 'V':
  89.           level |= DEBUG_TRACE_VERBOSE;
  90.           break;
  91.         default:
  92.           return -1;
  93.         }
  94.     }
  95.     }
  96.  
  97.   /*
  98.    * This is to avoid screwing up the trace output due to changes in
  99.    * the debug_level.
  100.    */
  101.   obstack_free (&trace, obstack_finish (&trace));
  102.  
  103.   return level;
  104. }
  105.  
  106. /*
  107.  * Change the debug output stream to FP.
  108.  */
  109. static void
  110. debug_set_file (FILE *fp)
  111. {
  112.   if (debug != NULL && debug != stderr)
  113.     fclose (debug);
  114.   debug = fp;
  115. }
  116.  
  117. /*
  118.  * Change the debug output to file NAME.  If NAME is NULL, debug output
  119.  * is reverted to stderr, and if empty debug output is discarded.
  120.  * Return TRUE iff the output stream was changed.
  121.  */
  122. boolean
  123. debug_set_output (char *name)
  124. {
  125.   FILE *fp;
  126.  
  127.   if (name == NULL)
  128.     debug_set_file (stderr);
  129.   else if (*name == '\0')
  130.     debug_set_file (NULL);
  131.   else
  132.     {
  133.       fp = fopen (name, "a");
  134.       if (fp == NULL)
  135.     return FALSE;
  136.  
  137.       debug_set_file (fp);
  138.     }
  139.   return TRUE;
  140. }
  141.  
  142. /*
  143.  * Generic function to do formatted output to the debug output stream.
  144.  * Usage as for printf ().
  145.  */
  146. void
  147. debug_print (va_alist)
  148.     va_dcl
  149. {
  150.   va_list args;
  151.   char *fmt;
  152.  
  153.   if (debug != NULL)
  154.     {
  155.       va_start (args);
  156.       fmt = va_arg (args, char *);
  157.       vfprintf (debug, fmt, args);
  158.       va_end (args);
  159.     }
  160. }
  161.  
  162. /*
  163.  * Print a one-line debug message, headed by "m4 debug".  Usage as for
  164.  * printf ().
  165.  */
  166. void
  167. debug_message (va_alist)
  168.     va_dcl
  169. {
  170.   va_list args;
  171.   char *fmt;
  172.  
  173.   if (debug != NULL)
  174.     {
  175.       fprintf (debug, "m4 debug: ");
  176.       if (debug_level & DEBUG_TRACE_FILE)
  177.     fprintf (debug, "%s: ", current_file);
  178.       if (debug_level & DEBUG_TRACE_LINE)
  179.     fprintf (debug, "%d: ", current_line);
  180.  
  181.       va_start (args);
  182.       fmt = va_arg (args, char *);
  183.       vfprintf (debug, fmt, args);
  184.       va_end (args);
  185.  
  186.       putc ('\n', debug);
  187.     }
  188. }
  189.  
  190.  
  191.  
  192. /*
  193.  * The rest of this file contains the functions for macro tracing
  194.  * output.  All tracing output for a macro call is collected on an
  195.  * obstack TRACE, and printed whenever the line is complete.  This
  196.  * prevents tracing output from interfering with other debug messages
  197.  * generated by the various builtins.
  198.  */
  199.  
  200.  
  201. /*
  202.  * Tracing output is formatted here, by a simplified printf-to-obstack
  203.  * function trace_format ().  Understands only %s, %d, %l (optional left
  204.  * quote) and %r (optional right quote).
  205.  */
  206. static void
  207. trace_format (va_alist)
  208.     va_dcl
  209. {
  210.   va_list args;
  211.   char *fmt;
  212.   char ch;
  213.  
  214.   int d;
  215.   char nbuf[32];
  216.   char *s;
  217.   int slen;
  218.   int maxlen;
  219.  
  220.   va_start (args);
  221.   fmt = va_arg (args, char *);
  222.  
  223.   while (TRUE)
  224.     {
  225.       while ((ch = *fmt++) != '\0' && ch != '%')
  226.     obstack_1grow (&trace, ch);
  227.  
  228.       if (ch == '\0')
  229.     break;
  230.  
  231.       maxlen = 0;
  232.       switch (*fmt++)
  233.     {
  234.     case 'S':
  235.       maxlen = max_debug_argument_length;
  236.       /* fall through */
  237.     case 's':
  238.       s = va_arg (args, char *);
  239.       break;
  240.     case 'l':
  241.       s = (debug_level & DEBUG_TRACE_QUOTE) ? lquote : "";
  242.       break;
  243.     case 'r':
  244.       s = (debug_level & DEBUG_TRACE_QUOTE) ? rquote : "";
  245.       break;
  246.     case 'd':
  247.       d = va_arg (args, int);
  248.       sprintf (nbuf, "%d", d);
  249.       s = nbuf;
  250.       break;
  251.     default:
  252.       s = "";
  253.       break;
  254.     }
  255.  
  256.       slen = strlen (s);
  257.       if (maxlen == 0 || maxlen > slen)
  258.     obstack_grow (&trace, s, slen);
  259.       else
  260.     {
  261.       obstack_grow (&trace, s, maxlen);
  262.       obstack_grow (&trace, "...", 3);
  263.     }
  264.     }
  265.  
  266.   va_end (args);
  267. }
  268.  
  269. /*
  270.  * Format the standard header attached to all tracing output lines.
  271.  */
  272.  
  273. static void
  274. trace_header (int id)
  275. {
  276.   trace_format ("m4trace:");
  277.   if (debug_level & DEBUG_TRACE_FILE)
  278.     trace_format ("%s:", current_file);
  279.   if (debug_level & DEBUG_TRACE_LINE)
  280.     trace_format ("%d:", current_line);
  281.   trace_format (" -%d- ", expansion_level);
  282.   if (debug_level & DEBUG_TRACE_CALLID)
  283.     trace_format ("id %d: ", id);
  284. }
  285.  
  286. /*
  287.  * Print current tracing line, and clear the obstack.
  288.  */
  289. static void
  290. trace_flush (void)
  291. {
  292.   char *line;
  293.  
  294.   obstack_1grow (&trace, '\0');
  295.   line = obstack_finish (&trace);
  296.   debug_print ("%s\n", line);
  297.   obstack_free (&trace, line);
  298. }
  299.  
  300. /*
  301.  * Do pre-argument-collction tracing for macro NAME.  Used from
  302.  * expand_macro ().
  303.  */
  304. void
  305. trace_prepre (char *name, int id)
  306. {
  307.   trace_header (id);
  308.   trace_format ("%s ...", name);
  309.   trace_flush ();
  310. }
  311.  
  312. /*
  313.  * Format the parts of a trace line, that can be made before the macro
  314.  * is actually expanded.  Used from expand_macro ().
  315.  */
  316. void
  317. trace_pre (char *name, int id, int argc, token_data **argv)
  318. {
  319.   int i;
  320.   const builtin *bp;
  321.  
  322.   trace_header (id);
  323.   trace_format ("%s", name);
  324.  
  325.   if (argc > 1 && (debug_level & DEBUG_TRACE_ARGS))
  326.     {
  327.       trace_format ("(");
  328.  
  329.       for (i = 1; i < argc; i++)
  330.     {
  331.       if (i != 1)
  332.         trace_format (", ");
  333.  
  334.       switch (TOKEN_DATA_TYPE (argv[i]))
  335.         {
  336.         case TOKEN_TEXT:
  337.           trace_format ("%l%S%r", TOKEN_DATA_TEXT (argv[i]));
  338.           break;
  339.         case TOKEN_FUNC:
  340.           bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv[i]));
  341.           if (bp == NULL)
  342.         internal_error ("builtin not found in builtin table! (trace_pre ())");
  343.           trace_format ("<%s>", bp->name);
  344.           break;
  345.         default:
  346.           internal_error ("Bad token data type (trace_pre ())");
  347.           break;
  348.         }
  349.  
  350.     }
  351.       trace_format (")");
  352.     }
  353.  
  354.   if (debug_level & DEBUG_TRACE_CALL)
  355.     {
  356.       trace_format (" -> ???");
  357.       trace_flush ();
  358.     }
  359. }
  360.  
  361.  
  362. /*
  363.  * Format the final part of a trace line and print it all.  Used from
  364.  * expand_macro ().
  365.  */
  366. void
  367. trace_post (char *name, int id, int argc, token_data **argv, char *expanded)
  368. {
  369.   if (debug_level & DEBUG_TRACE_CALL)
  370.     {
  371.       trace_header (id);
  372.       trace_format ("%s%s", name, (argc > 1) ? "(...)" : "");
  373.     }
  374.  
  375.   if (expanded && (debug_level & DEBUG_TRACE_EXPANSION))
  376.     trace_format (" -> %l%S%r", expanded);
  377.   trace_flush ();
  378. }
  379.